<!doctype html>
<html class="no-js" lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>
    
  iOS Block 知识点拾遗 - kaelinda
  
  </title>
  
  
  <link href="atom.xml" rel="alternate" title="kaelinda" type="application/atom+xml">
    <link rel="stylesheet" href="asset/css/foundation.min.css" />
    <link rel="stylesheet" href="asset/css/docs.css" />
    <script src="asset/js/vendor/modernizr.js"></script>
    <script src="asset/js/vendor/jquery.js"></script>
  <script src="asset/highlightjs/highlight.pack.js"></script>
  <link href="asset/highlightjs/styles/github.css" media="screen, projection" rel="stylesheet" type="text/css">
  <script>hljs.initHighlightingOnLoad();</script>
<script type="text/javascript">
  function before_search(){
    var searchVal = 'site:kaelinda.top ' + document.getElementById('search_input').value;
    document.getElementById('search_q').value = searchVal;
    return true;
  }
</script>
  </head>
  <body class="antialiased hide-extras">
    
    <div class="marketing off-canvas-wrap" data-offcanvas>
      <div class="inner-wrap">


<nav class="top-bar docs-bar hide-for-small" data-topbar>


  <section class="top-bar-section">
  <div class="row">
      <div style="position: relative;width:100%;"><div style="position: absolute; width:100%;">
        <ul id="main-menu" class="left">
        
        <li id=""><a target="_self" href="index.html">最近更新</a></li>
        
        <li id=""><a target="_self" href="archives.html">归档目录</a></li>
        
        <li id="ios.css"><a target="_self" href="ios.html">iOS</a></li>
        
        <li id="swift.css"><a target="_self" href="swift.html">Swift</a></li>
        
        <li id="reactnative.css"><a target="_self" href="reactnative.html">RN</a></li>
        
        <li id="js.css"><a target="_self" href="js.html">JS</a></li>
        
        <li id="shell.css"><a target="_self" href="shell.html">shell</a></li>
        
        <li id="coding.css"><a target="_self" href="coding.html">编程</a></li>
        
        <li id="live.css"><a target="_self" href="live.html">随笔</a></li>
        
        <li id="app.css"><a target="_blank" href="app.html">APP推荐</a></li>
        
        </ul>

        <ul class="right" id="search-wrap">
          <li>
<form target="_blank" onsubmit="return before_search();" action="http://google.com/search" method="get">
    <input type="hidden" id="search_q" name="q" value="" />
    <input tabindex="1" type="search" id="search_input"  placeholder="Search"/>
</form>
</li>
          </ul>
      </div></div>
  </div>
  </section>

</nav>

        <nav class="tab-bar show-for-small">
  <a href="javascript:void(0)" class="left-off-canvas-toggle menu-icon">
    <span> &nbsp; kaelinda</span>
  </a>
</nav>

<aside class="left-off-canvas-menu">
      <ul class="off-canvas-list">
        
        <li><a target="_self" href="index.html">最近更新</a></li>
        
        <li><a target="_self" href="archives.html">归档目录</a></li>
        
        <li><a target="_self" href="ios.html">iOS</a></li>
        
        <li><a target="_self" href="swift.html">Swift</a></li>
        
        <li><a target="_self" href="reactnative.html">RN</a></li>
        
        <li><a target="_self" href="js.html">JS</a></li>
        
        <li><a target="_self" href="shell.html">shell</a></li>
        
        <li><a target="_self" href="coding.html">编程</a></li>
        
        <li><a target="_self" href="live.html">随笔</a></li>
        
        <li><a target="_blank" href="app.html">APP推荐</a></li>
        

    <li><label>Categories</label></li>

        
            <li><a href="reactnative.html">React-Native</a></li>
        
            <li><a href="ios.html">iOS</a></li>
        
            <li><a href="app.html">MacAPP</a></li>
        
            <li><a href="swift.html">Swift</a></li>
        
            <li><a href="js.html">JavaScript</a></li>
        
            <li><a href="vue.html">Vue</a></li>
        
            <li><a href="shell.html">shell</a></li>
        
            <li><a href="%E7%BD%91%E7%BB%9C.html">网络</a></li>
         

      </ul>
    </aside>

<a class="exit-off-canvas" href="#"></a>


        <section id="main-content" role="main" class="scroll-container">
        
       

 <script type="text/javascript">
  $(function(){
    $('#menu_item_index').addClass('is_active');
  });
</script>
<div class="row">
  <div class="large-8 medium-8 columns">
      <div class="markdown-body article-wrap">
       <div class="article">
          
          <h1>iOS Block 知识点拾遗</h1>
     
        <div class="read-more clearfix">
          <span class="date">2018/3/3</span>

          <span>posted in&nbsp;</span> 
          
              <span class="posted-in"><a href='ios.html'>iOS</a></span>
           
         
          <span class="comments">
            

            
          </span>

        </div>
      </div><!-- article -->

      <div class="article-content">
      <ol>
<li><p>Block为什么要用copy</p>
<ul>
<li>block在创建的时候默认分配的内存是在栈上，而不是在堆上。这样的话其本身的作用域是属于创建时候的作用域，一旦在创建的作用域之外调用就会导致程序的崩溃。所以使用了copy将其拷贝到堆内存上。</li>
<li>block创建在栈上，而block的代码中可能会用到本地的一些变量，在栈上可能随时会被系统释放掉，只有将其拷贝到堆上，才能一直保持Block的存在，并用这些外部变量</li>
</ul></li>
<li><p>Block为什么不用retain</p>
<ul>
<li>retain只是增加了一次引用计数，block的内存还是在栈上，并没有存在堆上，存在栈上的block可能随时被系统回收</li>
</ul></li>
<li><p>为什么进入block中的对象引用计数需要自动加1？</p>
<ul>
<li>Block执行的是回调，因此block并不知道其中的对象obj创建后会在什么时候被释放，为了不在block使用obj之前，对象已经被释放，block就retain了obj一次</li>
</ul></li>
<li><p>block和函数的关系</p>
<ul>
<li>Block的使用很<strong>像函数指针</strong>，不过与函数最大的不同是Block可以访问函数以外、词法作用域以内的外部变量的值。换句话说，Block不仅 实现函数的功能，还能<strong>携带函数的执行环境</strong>。</li>
<li>函数指针 <code>void(*fun)(int)</code></li>
<li>block <code>void(^fun)(int)</code></li>
</ul></li>
<li><p>block本质（对于block的理解）<a href="https://www.cnblogs.com/yoon/p/4953618.html">请查阅Block实现原理</a></p>
<ul>
<li>block实际上是: 指向结构体的指针</li>
<li>编译器会将block的内部代码生成对应的函数</li>
</ul></li>
<li><p>对于基本数据类型，进入到block中会被当做常量处理。对象 retain 会一次</p>
<span id="more"></span><!-- more -->
<pre><code class="language-text">//如果需要在block中对num进行修改，需要加上关键字__block
//(我们也可以用static关键字进行修饰)<br/>
int  num1 = 10;<br/>
void(^block1)() = ^{<br/>
   NSLog(@&quot;num1 is %d&quot;,num1);<br/>
};<br/>
num1 = 20;<br/>
block1(); //输出10<br/>
//改进:使用block,使进入到block块中的变量不被当做常量来使用<br/>
__block int  num2 = 10;<br/>
void(^block2)() = ^{<br/>
 NSLog(@&quot;num2 is %d&quot;,num2);<br/>
};<br/>
num2 = 20;<br/>
block2(); //输出20
</code></pre></li>
<li><p>Block中self的循环引用</p>
<ul>
<li>block默认创建在栈上，所以对要对其进行执行copy操作，将其拷贝到堆区，便于更好的操作对象。但是执行了copy操作之后，block中使用self，此对象会被retain一次（注意：block在堆区上时才会起到retain作用），会造成循环引用。</li>
<li>解决方法：
<ul>
<li>在MRC下，使用__block修饰</li>
<li>在ARC下，使用__unsafe_unretained\weak修饰</li>
</ul></li>
</ul></li>
<li><p>Block 在内存中的分类</p>
<ul>
<li>全局block --&gt; GlobalBlock &lt;==&gt; 相当于全局变量, 系统会自动释放</li>
<li>栈block --&gt; StackBlock &lt;==&gt; 相当于局部变量, 系统会自动释放</li>
<li>堆block --&gt; MallocBlock &lt;==&gt; (需要手动释放内存)</li>
</ul></li>
<li><p>block类型区分方法</p>
<ul>
<li>如果block实现中没有访问任何&quot;外部&quot;变量(包括局部和全局), 该block为GlobalBlock</li>
<li>如果block实现中访问了任何&quot;外部&quot;变量(包括局部和全局), 该block为StackBlock</li>
<li>对StackBlock进行拷贝(copy/Block_copy), 该block为MallocBlock</li>
</ul></li>
<li><p>block内如何修改block外 的变量?</p>
<pre><code class="language-text"> __block int a = 0;
   void (^foo)(void) = ^{ <br/>
       a = 1; <br/>
   };<br/>
   foo(); <br/>
   //这里，a的值被修改为1
</code></pre>
<p>默认情况下，block内访问的变量是 copy  该变量到堆后的变量，而非变量本身。<br/>
所以：<strong>读写操作对原变量不生效</strong></p>
<blockquote>
<p>我们知道：Block不允许修改外部变量的值，这里所说的外部变量的值，指的是栈中指针的内存地址。__block 所起到的作用就是只要观察到该变量被 block 所持有，就将“外部变量”在栈中的内存地址放到了堆中。进而在block内部也可以修改外部变量的值</p>
</blockquote>
<pre><code class="language-text">__block int a = 0;
   NSLog(@&quot;定义前：%p&quot;, &amp;a);         //栈区<br/>
   void (^foo)(void) = ^{<br/>
       a = 1;<br/>
       NSLog(@&quot;block内部：%p&quot;, &amp;a);    //堆区<br/>
   };<br/>
   NSLog(@&quot;定义后：%p&quot;, &amp;a);         //堆区<br/>
   foo();
</code></pre>
<p>打印输出：</p>
<pre><code class="language-text">2016-05-17 02:03:33.559 LeanCloudChatKit-iOS[1505:713679] 定义前：0x16fda86f8
2016-05-17 02:03:33.559 LeanCloudChatKit-iOS[1505:713679] 定义后：0x155b22fc8<br/>
2016-05-17 02:03:33.559 LeanCloudChatKit-iOS[1505:713679] block内部： 0x155b22fc8
</code></pre></li>
<li><p>block个人理解</p>
<pre><code class="language-text">NSMutableString *kName = [NSMutableString stringWithString:@&quot;kael&quot;];
__block NSMutableString *myname = kName;<br/>
NSLog(@&quot;block 前%p&quot;,&amp;myname);<br/>
void (^foo)(void) = ^(){<br/>
    NSLog(@&quot;block 中1：%p&quot;,&amp;myname);<br/>
    myname = [NSMutableString stringWithString:@&quot;kaelinda&quot;];<br/>
    NSLog(@&quot;block 中2：%p&quot;,&amp;myname);<br/>
};<br/>
foo();<br/>
NSLog(@&quot;block 后%p&quot;,&amp;myname);<br/>
/**<br/>
 * __block 修饰之前<br/>
 * 外部变量的内存地址是存到了栈<br/>
 * block 是在堆内，不清楚栈内的变量是否已经被释放，所以连引用的准确性都是问题，更谈不上是修改了<br/>
 * 所以，block 不允许修改栈中的变量（或者栈中指针的内存地址）<br/>
 */<br/>
/**<br/>
 * __block 修饰之后<br/>
 * 初始化的时候，内存地址在栈内（因为并不确定block内是否会用到），<br/>
 * 当检测到block内引用到了该对象，不管block有没有被调用，都会 从栈内 copy 内存地址到 堆内，<br/>
 * 再操作的时候 操作的是堆内的内存地址<br/>
 */
</code></pre></li>
</ol>


    

      </div>

      <div class="row">
        <div class="large-6 columns">
        <p class="text-left" style="padding:15px 0px;">
      
          <a href="15222179789382.html" 
          title="Previous Post: iOS GCD&&多线程">&laquo; iOS GCD&&多线程</a>
      
        </p>
        </div>
        <div class="large-6 columns">
      <p class="text-right" style="padding:15px 0px;">
      
          <a  href="15200715202464.html" 
          title="Next Post: iOS 离屏渲染">iOS 离屏渲染 &raquo;</a>
      
      </p>
        </div>
      </div>
      <div class="comments-wrap">
        <div class="share-comments">
          

          

          
        </div>
      </div>
    </div><!-- article-wrap -->
  </div><!-- large 8 -->




 <div class="large-4 medium-4 columns">
  <div class="hide-for-small">
    <div id="sidebar" class="sidebar">
          <div id="site-info" class="site-info">
            
                <div class="site-a-logo"><img src="https://ws1.sinaimg.cn/large/006tNc79ly1fmpk9088gsj30sg0sgn33.jpg" /></div>
            
                <h1>kaelinda</h1>
                <div class="site-des">倘若我心中的山水，你眼中能看到，我便一步一莲花祈祷</div>
                <div class="social">








<a target="_blank" class="twitter" target="_blank" href="https://twitter.com/KaelLVLinda" title="Twitter">Twitter</a>
<a target="_blank" class="github" target="_blank" href="https://github.com/Kaelzzs" title="GitHub">GitHub</a>
<a target="_blank" class="email" href="mailto:zhouzuosong_kael@163.com" title="Email">Email</a>
  <a target="_blank" class="rss" href="atom.xml" title="RSS">RSS</a>
                
              	 </div>
          	</div>

             

              <div id="site-categories" class="side-item ">
                <div class="side-header">
                  <h2>Categories</h2>
                </div>
                <div class="side-content">

      	<p class="cat-list">
        
            <a href="reactnative.html"><strong>React-Native</strong></a>
        
            <a href="ios.html"><strong>iOS</strong></a>
        
            <a href="app.html"><strong>MacAPP</strong></a>
        
            <a href="swift.html"><strong>Swift</strong></a>
        
            <a href="js.html"><strong>JavaScript</strong></a>
        
            <a href="vue.html"><strong>Vue</strong></a>
        
            <a href="shell.html"><strong>shell</strong></a>
        
            <a href="%E7%BD%91%E7%BB%9C.html"><strong>网络</strong></a>
         
        </p>


                </div>
              </div>

              <div id="site-categories" class="side-item">
                <div class="side-header">
                  <h2>Recent Posts</h2>
                </div>
                <div class="side-content">
                <ul class="posts-list">
	      
		      
			      <li class="post">
			        <a href="15523077857608.html">OC中枚举写法  以及 字符串枚举探索</a>
			      </li>
		     
		  
		      
			      <li class="post">
			        <a href="15522686353535.html">iOS 动画全解 (1)</a>
			      </li>
		     
		  
		      
			      <li class="post">
			        <a href="15501356584731.html">UITableView顶部空白的几种解决办法</a>
			      </li>
		     
		  
		      
			      <li class="post">
			        <a href="15488351784332.html">Objective-C中的字符串类型枚举 探索</a>
			      </li>
		     
		  
		      
			      <li class="post">
			        <a href="15409691048860.html">【Swift笔记】引用计数</a>
			      </li>
		     
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		  
		      
		   
		  		</ul>
                </div>
              </div>
        </div><!-- sidebar -->
      </div><!-- hide for small -->
</div><!-- large 4 -->

</div><!-- row -->

 <div class="page-bottom clearfix">
  <div class="row">
   <p class="copyright">Copyright &copy; 2015
Powered by <a target="_blank" href="http://www.mweb.im">MWeb</a>,&nbsp; 
Theme used <a target="_blank" href="http://github.com">GitHub CSS</a>.</p>
  </div>
</div>

        </section>
      </div>
    </div>

  
    

    <script src="asset/js/foundation.min.js"></script>
    <script>
      $(document).foundation();
      function fixSidebarHeight(){
        var w1 = $('.markdown-body').height();
          var w2 = $('#sidebar').height();
          if (w1 > w2) { $('#sidebar').height(w1); };
      }
      $(function(){
        fixSidebarHeight();
      })
      $(window).load(function(){
          fixSidebarHeight();
      });
     
    </script>

    
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script><script type="text/x-mathjax-config">MathJax.Hub.Config({TeX: { equationNumbers: { autoNumber: "AMS" } }});</script>


  </body>
</html>
